package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type Info struct { //只通过结构字段表述信息有限
	Name   string `json:"name"`          // 此处tag按照encoding/json包的规则 输出字段名为小写的 name
	Age    int    `json:"age,omitempty"` // 此处tag按照encoding/json包的规则，设置字段名和omitempty规则，如果为空则不输出
	Gender string
}

// 自己定义解析struct tag
type MyInfo struct {
	Name   string `mytag:"name,max_length=17,min_length=5"`
	Age    int    `mytag:"age,min=18,max=70"`
	Gender string `mytag:"gender,required"`
}

func main() {
	// 结构体标签
	/*
		结构体的字段除了名字和类型外，还可以有一个可选的标签（tag），他是一个附属于字段的字符串，可以是文档或其他的重要标记，
		比如我们解析json或生成json文件时，需要使用到 encoding/json包，它提供一些默认标签，例如 omitempty标签可以在序列化的时候
		忽略0值或者空值，而-标签的作用是不进行序列化，其效果和直接将结构体中的字段写成小写的效果一样。
	*/
	info := Info{
		Name:   "zhangsan",
		Gender: "男",
	}
	re, _ := json.Marshal(info)
	fmt.Println(string(re)) // 返回的值为 []byte需要转为string
	// 通过反射包识别这些tag
	info2 := MyInfo{
		Name:   "zhangsan",
		Gender: "男",
	}
	t := reflect.TypeOf(info2)
	fmt.Println(t.Name())
	fmt.Println(t.Kind())
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i) // 获取结构体的每一个字段
		tag := field.Tag.Get("mytag")
		fmt.Printf("%d. %v (%v) , tag '%v'\n", i+1, field.Name, field.Type.Name(), tag)
	}
	// 具体应用大部分情况下，我们是不需要使用到反射的 开发一些底层库用的会比较多
}
